package com.woniuxy.service.impl;

import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.conmon.Assert;
import com.woniuxy.conmon.enums.BusinessCode;
import com.woniuxy.conmon.enums.RedisConst;
import com.woniuxy.conmon.enums.UserStatus;
import com.woniuxy.mapper.UserMapper;
import com.woniuxy.pojo.SysRole;
import com.woniuxy.pojo.SysRoleUser;
import com.woniuxy.pojo.User;
import com.woniuxy.pojo.dto.*;
import com.woniuxy.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 *
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    SysRoleUserServiceImpl sysRoleUserService;

    @Autowired
    SysRoleServiceImpl sysRoleService;

    @Override
    public ResponseEntity login(LoginDTO dto) {
        //先判断验证码是否正确
        String key = dto.getKey();
        String code = redisTemplate.opsForValue().get(key).toString();
        Assert.error(!dto.getCode().equals(code), BusinessCode.VERIFICATION_ERROR);

        //1.判断用户名是否存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(User::getUsername,dto.getUsername());
        User user = userMapper.selectOne(wrapper);
        Assert.error(user==null,BusinessCode.USER_NOT_EXIST);

//        2.判断密码是否正确
        boolean checkpw = BCrypt.checkpw(dto.getPassword(), user.getPassword());
        Assert.error((!checkpw),BusinessCode.PASSWORD_ERROR);
//        3.判断用户状态
        Assert.error(user.getStatus() != UserStatus.ACTIVE.getKey().byteValue(),BusinessCode.USER_FROZEN_ERROR);
        return ResponseEntity.ok(user);
    }

    @Override
    public User findTel(String telephone) {
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).eq(User::getPhone,telephone);

        return userMapper.selectOne(wrapper);
    }

    @Override
    public boolean emailExists(String email) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail,email);
        User user = userMapper.selectOne(wrapper);
        return user!=null;
    }

    @Override
    public User findEmail(String email) {
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).eq(User::getEmail, email);

        return userMapper.selectOne(wrapper);
    }

    @Override
    public User createNewAccount(RegisterDTO dto) {
        //1.判断验证码是否过期
        String s = redisTemplate.opsForValue().get(RedisConst.EMAIL_ADDRESS_PREFIX + ":" + dto.getEmail()).toString();
        Assert.error(s == null,BusinessCode.INVALID_VERIFICATION);
        //2.判断验证码是否正确
        Assert.error(!dto.getCode().equals(s),BusinessCode.VERIFICATION_ERROR);
        //3.判断用户名是否存在
        Assert.error(accountExists(dto.getUsername()),BusinessCode.USER_IS_EXIST);
        //4.判断手机号是否存在
        Assert.error(phoneExists(dto.getMobile()),BusinessCode.MOBILE_IS_EXIST);

        //5.判断通过新增用户
        User user = new User();
        BeanUtils.copyProperties(dto,user);
        user.setStatus(UserStatus.ACTIVE.getKey());
        user.setPassword(BCrypt.hashpw(dto.getPassword()));
        userMapper.insert(user);
        return user;
    }

    @Override
    public boolean accountExists(String account) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,account);
        User user = userMapper.selectOne(wrapper);
        return user!=null;
    }

    @Override
    public boolean phoneExists(String phone) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPhone,phone);
        User user = userMapper.selectOne(wrapper);
        return user!=null;
    }

    @Override
    public Boolean moveAccount(Integer id) {
        int i = userMapper.deleteById(id);
        return i>0;
    }

    @Override
    public Boolean batchRemove(List<Integer> ids) {
        return ids.stream()
                .map(this::moveAccount)
                .allMatch(Boolean::booleanValue);
    }

    @Override
    public Boolean saveChangeUser(Integer userId, UserDTO dto) {
        LambdaUpdateWrapper<User> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(User::getId,userId)
                .set(User::getUsername,dto.getUsername())
                .set(User::getDepartment,dto.getDepartment())
                .set(User::getNickname,dto.getNickname())
                .set(User::getPhone,dto.getPhone())
                .set(User::getPassword,dto.getPassword());
        SysRole role = sysRoleService.getById(dto.getRole());
        wrapper.set(User::getRole,role.getRoleName());

        //为用户更改角色
        LambdaQueryWrapper<SysRoleUser> wrapper1 = Wrappers.lambdaQuery(SysRoleUser.class).eq(SysRoleUser::getUserId, userId);
        sysRoleUserService.remove(wrapper1);
        SysRoleUser sysRoleUser = new SysRoleUser();
        sysRoleUser.setUserId(userId);
        sysRoleUser.setRoleId(dto.getRole());
        sysRoleUserService.save(sysRoleUser );
        return userMapper.update(null,wrapper)>0;
    }

    @Override
    public Boolean addAccount(UserDTO dto) {

        User user = new User();
        BeanUtils.copyProperties(dto,user);
        user.setIsSys(1L);

        int rows = userMapper.insert(user);

        return rows > 0;
    }

    @Override
    public Boolean removePreUser(Integer id) {
        return userMapper.deleteById(id) > 0;
    }

    @Override
    public Boolean batchRemPreUser(List<Integer> ids) {
        return ids.stream()
                .map(this::removePreUser)
                .allMatch(Boolean::booleanValue);
    }

    @Override
    public List<RegionUserCountDTO> getUserCountByRegion() {
        return userMapper.countUsersByRegion();
    }

    @Override
    public GenderStatisticsDTO getGenderStatistics() {
        return userMapper.getGenderStatistics();
    }

    @Override
    public List<AgeDistributionDTO> getAgeDistributionWithPercentage() {
        List<AgeDistributionDTO> list = userMapper.getAgeDistribution();
        int total = list.stream().mapToInt(AgeDistributionDTO::getCount).sum();

        for (AgeDistributionDTO dto : list) {
            double percentage = total == 0 ? 0 : (dto.getCount() * 100.0 / total);
            dto.setPercentage(Math.round(percentage * 10.0) / 10.0); // 保留 1 位小数
        }

        return list;
    }
}




